<template>
  <div class="container" @click="unlockAudio">
    <canvas ref="canvas" :width="width" :height="height"></canvas>
    <!-- 隐藏的音频元素 -->
    <audio ref="jumpSound" src="/audio/pa.mp3" preload="auto"></audio>
  </div>
</template>

<script lang="ts" setup>
import { ref, onMounted } from 'vue'

const height = window.innerHeight
const width = window.innerWidth
const canvas = ref<HTMLCanvasElement | null>(null)
const jumpSound = ref<HTMLAudioElement | null>(null) // 音频引用
const audioUnlocked = ref(false) // 是否已解锁音频
const scale = 5
const offsetY = 300 // 下移整体偏移量

// 火柴人状态
const state = ref({
  x: width / 2,
  y: height / 2 + offsetY,
  ropeAngle: 0,
  isJumping: false,
  jumpHeight: 0,
  jumpDirection: 1,
  count: 0,
  soundPlayed: false // 标记音效是否已播放
})

// 常量配置
const config = {
  ropeSpeed: 0.08,
  ropeLength: 120 * scale,
  ropeLeftX: width / 2 - 120 * scale,
  ropeRightX: width / 2 + 120 * scale,
  maxJumpHeight: 50 * scale,
  jumpSpeed: 4 * scale,
  soundThreshold: 0.1 // 判断最低点的阈值
}

// 动态计算脚的位置
function getFootY() {
  return state.value.y - 50 * scale * 1.2 // 图片人物脚部偏移
}

// 加载人物图片
const characterImg = new Image()
characterImg.src = '/images/people.png' // 替换为你的人物图片路径

let lastRopeMiddleY = 0

function updateJump() {
  const footY = getFootY()
  const ropeMiddleY = footY + config.ropeLength * Math.cos(state.value.ropeAngle)

  // 检测绳子是否接近最低点
  const isNearBottom = Math.abs(Math.cos(state.value.ropeAngle) - 1) < config.soundThreshold

  if (isNearBottom && !state.value.soundPlayed) {
    playJumpSound()
    state.value.soundPlayed = true
  } else if (!isNearBottom) {
    state.value.soundPlayed = false
  }

  if (!state.value.isJumping && lastRopeMiddleY > footY && ropeMiddleY <= footY) {
    state.value.isJumping = true
    state.value.jumpDirection = 1
  }

  if (state.value.isJumping) {
    state.value.jumpHeight += state.value.jumpDirection * config.jumpSpeed
    if (state.value.jumpHeight >= config.maxJumpHeight) state.value.jumpDirection = -1
    if (state.value.jumpHeight <= 0) {
      state.value.jumpHeight = 0
      state.value.isJumping = false
      state.value.count++
    }
  }

  lastRopeMiddleY = ropeMiddleY
}

// 🔊 解锁音频：用户第一次点击时调用
function unlockAudio() {
  if (jumpSound.value && !audioUnlocked.value) {
    jumpSound.value
      .play()
      .then(() => {
        if (jumpSound.value) {
          jumpSound.value.pause()
          jumpSound.value.currentTime = 0
        }
        audioUnlocked.value = true
        console.log('音频已解锁 ✅')
      })
      .catch((e) => {
        console.warn('音频解锁失败:', e)
      })
  }
}

// 播放跳跃音效
function playJumpSound() {
  if (jumpSound.value && audioUnlocked.value) {
    jumpSound.value.currentTime = 0 // 重置播放位置
    jumpSound.value.play().catch((e) => {
      console.warn('音效播放失败:', e)
    })
  }
}

// 绘制人物图片
function drawCharacter(ctx: CanvasRenderingContext2D) {
  const drawY = state.value.y - state.value.jumpHeight - 100 * scale // 图片高度偏移
  const drawX = state.value.x - 50 * scale // 图片宽度偏移
  ctx.drawImage(characterImg, drawX, drawY, 100 * scale, 100 * scale)
}

// 绘制跳绳
function drawJumpRope(ctx: CanvasRenderingContext2D) {
  const footY = getFootY()
  const ropeMiddleY = footY + config.ropeLength * Math.cos(state.value.ropeAngle)

  ctx.beginPath()
  ctx.moveTo(config.ropeLeftX, footY)
  ctx.quadraticCurveTo(state.value.x, ropeMiddleY, config.ropeRightX, footY)
  ctx.stroke()

  ctx.beginPath()
  ctx.moveTo(config.ropeLeftX, footY)
  ctx.lineTo(config.ropeLeftX, footY + 20 * scale)
  ctx.moveTo(config.ropeRightX, footY)
  ctx.lineTo(config.ropeRightX, footY + 20 * scale)
  ctx.stroke()
}

// 绘制计数器
function drawCounter(ctx: CanvasRenderingContext2D) {
  ctx.fillStyle = 'rgba(255,255,255,0.7)'
  ctx.fillRect(10, 10, 150, 30)
  ctx.font = `${20}px Arial`
  ctx.fillStyle = 'black'
  ctx.fillText('跳绳次数: ', 20, 35)
  ctx.fillStyle = 'red'
  ctx.fillText(state.value.count.toString(), 110, 35)
}

// 动画循环
function animate(ctx: CanvasRenderingContext2D) {
  if (!canvas.value) return
  ctx.clearRect(0, 0, canvas.value.width, canvas.value.height)
  state.value.ropeAngle += config.ropeSpeed
  if (state.value.ropeAngle > Math.PI * 2) state.value.ropeAngle = 0

  updateJump()
  drawJumpRope(ctx)
  drawCharacter(ctx)
  drawCounter(ctx)

  requestAnimationFrame(() => animate(ctx))
}

onMounted(() => {
  if (!canvas.value) return
  const ctx = canvas.value.getContext('2d')
  if (!ctx) return // 增加空判断
  ctx.lineWidth = 2 * scale
  characterImg.onload = () => animate(ctx)
})
</script>

<style scoped lang="scss">
.container {
  background: #f5f5f5;
  position: relative;
  height: 100vh;
  width: 100vw;
}
canvas {
  display: block;
  margin: 0 auto;
  background: #fff;
  border: 2px solid #ddd;
}
audio {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}
</style>
